#pragma once

#include <string>
#include <cstdlib>
#include <assert.h>
#include <math.h>

//#include "api/Vector2.h"
#include "api/GameInfo.h"
#include "Utils.h"

using namespace std;

namespace EAction
{
    enum Type
    {
        CoverPosition = 0,
        DefensiveMove,

        _MoveActionsStart,
        SimpleMove,
        Move,
        _MoveActonsEnd,
    };

    bool IsMoveAction(Type t);
};

namespace EResult
{
    enum Type
    {
        Success,
        Failure,
        InProgress,
    };
}

class MyCommander;


class Action
{
public:
    virtual void Update(float dt) = 0;
    
    EResult::Type GetResult() const { return m_Result; }
    EAction::Type GetType() const { return m_Type; }

protected:
    Action(MyCommander* commander, const string& bot_name, const string& comment, EAction::Type type)
        : m_Commander(commander), m_Type(type), m_BotName(bot_name), m_Comment(comment), m_Result(EResult::InProgress) {}

    MyCommander* m_Commander;
    EAction::Type m_Type;
    string m_BotName;
    string m_Comment;

    EResult::Type m_Result;
};


class MoveAction : public Action
{
public:
    virtual Vector2 GetDest() const  { return m_Dest; }

protected:
    MoveAction(MyCommander* commander, const string& bot_name, const string& comment, EAction::Type type, const Vector2& dest)
        : Action(commander, bot_name, comment, type), m_Dest(dest) {}

    Vector2 m_Dest;
};


class CoverPosition : public Action
{
public:
    CoverPosition(MyCommander* commander, const string& bot_name, const string& comment, const Vector2& dir, float time);

    virtual void Update(float dt);

private:
    float m_CurrentTime;
    float m_Time;
    Vector2 m_Direction;
};


class SimpleMove : public MoveAction
{
public:
    SimpleMove(MyCommander* commander, const string& bot_name, const string& comment, const Vector2& dest, bool charge = false);

    virtual void Update(float dt);

private:
    bool m_OrderIssued;
    bool m_Charge;
};


class Move : public MoveAction
{
public:
    Move(MyCommander* commander, const string& bot_name, const string& comment, const Vector2& dest, bool charge = false);

    virtual void Update(float dt);

private:
    bool m_OrderIssued;
    bool m_Charge;
    Path m_Path; // not smoothed
    Path m_PathSmoothed;
};


class DefensiveMove : public Action
{
public:
    DefensiveMove(MyCommander* commander, const string& bot_name, const string& comment, const Vector2& origin);

    virtual void Update(float dt);

private:
    void GeneratePath(Path& path);

    Vector2 m_Origin;
    bool m_OrderIssued;
};